import store from 'store/store';
import { formatDate } from 'common/tool';

class DB {
  constructor(dbName) {
    this.dbName = dbName;
  }

  /**
   * 获取当前 redux 中存储的 store name
   */
  getCurrentStore() {
    return store.getState().date;
  }

  /**
   * 连接数据库
   */
  connectDB() {
    return new Promise((resolve, reject) => {
      const indexedDB = window.indexedDB || window.mozIndexedBD || window.webkitIndexedDB || window.msIndexedDB;
      if (!indexedDB) {
        reject(new Error('无法访问本地数据'));
      }
      this.indexedDB = indexedDB;
      const request = indexedDB.open(this.dbName);
      request.onerror = reject;
      request.onupgradeneeded = e => {
        this.dbConnect = request.result;
        request.result.createObjectStore(formatDate(new Date(), 'YYYYMMDD'), { autoIncrement: true });
        request.transaction.oncomplete = resolve;
      }
      request.onsuccess = e => {
        this.dbConnect = request.result;
        resolve(e);
      }
    });
  }
  /**
   * 更新数据库版本并创建 Store
   */
  updateVersion(storeName) {
    return new Promise((resolve, reject) => {
      const dbConnect = this.dbConnect;
      const version = dbConnect.version + 1;
      dbConnect.close();  // 关闭当前版本的数据库
      const request = this.indexedDB.open(this.dbName, version);

      // 第一次调用生成当天数据库
      request.onupgradeneeded = event => {
        this.dbConnect = event.target.result;
        const transaction = event.target.transaction;
        // 此处有 BUG，一个事务中不能处理多个创建操作。
        storeName.forEach(store => {
          this.dbConnect.createObjectStore(store, { autoIncrement: true });
        });
        transaction.oncomplete = resolve;
      }

      request.onerror = reject;
    });
  }

  /**
   * 获取事务
   */
  getTransaction(storeName, right = 'readwrite') {
    storeName = Array.isArray(storeName) ? storeName : [storeName];
    return new Promise((resolve, reject) => {
      const dbConnect = this.dbConnect
      const existStoreNames = dbConnect.objectStoreNames; // 已存在的store
      // 需要创建的 store
      const neededStores = storeName.reduce((arr, name) => {
        existStoreNames.contains(name) || arr.push(name);
        return arr;
      }, []);
      // 如果所有 store 都存在则直接创建事务
      if (neededStores.length === 0) {
        resolve(dbConnect.transaction(storeName, right));
        return;
      }
      // 否则升级数据库来创建不存的 store
      this.updateVersion(neededStores).then(() => {
        resolve(this.dbConnect.transaction(storeName, right));
      }).catch(reject);
    });
  }

  /**
   * 获取 Store
   */
  getStore(storeName, stores, right) {
    stores = stores || storeName;
    return this.getTransaction(storeName, right).then(transaction => {
      return transaction.objectStore(storeName);
    });
  }

  /**
   * 获取整个 Store 内容
   */
  getAll(storeName, stores) {
    stores = stores || storeName;
    return this.getStore(storeName, stores).then(store => {
      const result = [];
      store.openCursor(null, "prev").onsuccess = event => {
        const cursor = event.target.result;
        if (cursor) {
          cursor.value.id = cursor.key;
          result.push(cursor.value);
          cursor.continue();
        }
      }
      return new Promise((resolve, reject) => {
        store.transaction.oncomplete = () => {
          resolve(result);
        }
        store.transaction.onerror = reject;
      })
    });
  }

  /**
   * 插入数据
   * @param storeName
   * @param {要插入数据} data 
   * @param {插入数据的key} key
   */
  insert(storeName, data, key) {
    return this.getStore(storeName).then(store => {
      const request = store.add(data, key);
      return new Promise((resolve, reject) => {
        store.transaction.oncomplete = () => {
          resolve(request.result);
        }
        store.transaction.onerror = reject;
      })
    });
  }

  /**
   * 插入数据并更新 Redux
   * @param {要出入的数据} data
   */
  insertRx(data) {
    const storeName = this.getCurrentStore();
    console.log(storeName);
    return this.insert(storeName, data, data.id).then(res => {
      data.id = res;
      store.dispatch({
        type: 'ADD_ITEM',
        data,
      });
    });
  }


  /**
   * 更新数据
   * @param {数据} data 
   * @param {键值} key 
   */
  update(storeName, data, key, updateRedux = true) {
    return this.getStore(storeName).then(store => {
      const request = store.put(data, key);
      return new Promise((resolve, reject) => {
        request.transaction.oncomplete = resolve;
        request.transaction.onerror = reject;
      });
    })
  }

  /**
   * 更新数据库和 redux 数据
   * @param {要更新的数据} data 
   */
  updateRx(data) {
    // 获取当前数据库
    const storeName = this.getCurrentStore();
    console.log(storeName);
    return this.update(storeName, data, data.id).then(() => {
      store.dispatch({
        type: 'UPDATE_ITEM',
        data,
      });
    });
  }

  /**
   * 删除数据库数据
   * @param {键值} key 
   */
  delete(storeName, key) {
    return this.getStore(storeName).then(store => {
      const request = store.delete(key);
      return new Promise ((resolve, reject) => {
        request.transaction.oncomplete = resolve;
        request.transaction.onerror = reject;
      });
    });
  }

  deleteRx(id) {
    const storeName = this.getCurrentStore();
    console.log(storeName);
    return this.delete(storeName, id).then(() => {
      store.dispatch({
        type: 'DELETE_ITEM',
        data: id,
      });
    });
  }
}

export default DB;
